/*
*   cpu.h
*   Author: Dustin Striplin, Wilson Burhan, Bill Minter
*   Controls the processes and the interrupt generating devices
*/

#include <pthread.h>

#include "global.h"
#include "Packet.h"
#include "ProcessADT.h"
#include "pcb.h"
#include "Queue.h"
#include "Request.h"
#include "IOdevice.h"
#include "Mutex.h"
#include "ConditionVariable.h"

#ifndef CPU_H
#define CPU_H

typedef struct cpu{
    QueuePtr allPCB; //store all pcb's and processes in here for easy destruction at the end. (call destructAll on the queue)
    unsigned int step_no; //the current count
    int isRunning;
    int numProducerConsumer;
    int numCVs;
    IODevicePtr* ioDevices; //an array that holds all of of the io devices.
    MutexPtr* mutexes; //an array that holds all of the mutexes (1 for each producer consumer pair)
    CVPtr* cvs;     //an array that holds all fo the condition variables(1 for each producer consumer pair)
    int* sharedMemory; //an array that holds the memory block that's shared between producer/consumer
    PCBPtr running;      //the currently running process
    PCBPtr idl;
    QueuePtr readyQueue;     //the ready queue
    pthread_t* threads;      //an array for managing the threads
    pthread_mutex_t mutexRQ; //controls changes to the ready queues

    void(*destruct)(struct cpu*);
    PacketPtr(*step)(struct cpu*);
    int(*scheduler)(struct cpu*);   //can easily change the scheduler
    void(*notifyObserver)(PacketPtr); //notify observer of an interrupt
}CPUStr;

typedef CPUStr* CPUPtr;

CPUPtr cpuConstructor(int numComputeBound, int numProducerConsumer, void(*notifyObserver)(PacketPtr));
void cpuDestructor(CPUPtr this);
void *Timer(void *this);
void *IODevice(void *this);
void *KeyboardDevice(void *this);

PacketPtr cpuStep(CPUPtr this);


//kernal space functions
int cpuRRScheduler(CPUPtr this);
int cpuTimer_int_handler(CPUPtr this);
int io_int_handler(CPUPtr this, int ioID);
PacketPtr io_req_trap_handler(CPUPtr this, RequestPtr request);
PacketPtr mutex_lock_trap_handler(CPUPtr this, RequestPtr request);
PacketPtr mutex_unlock_trap_handler(CPUPtr this, RequestPtr request);
PacketPtr cond_wait_trap_handler(CPUPtr this, RequestPtr request);
PacketPtr cond_signal_trap_handler(CPUPtr this, RequestPtr request);

//user space functions
PacketPtr io_system_call(CPUPtr this, RequestPtr request);
PacketPtr mutex_lock_system_call(CPUPtr this, RequestPtr request);
PacketPtr mutex_unlock_system_call(CPUPtr this, RequestPtr request);
PacketPtr cond_wait_system_call(CPUPtr this, RequestPtr request);
PacketPtr cond_signal_system_call(CPUPtr this, RequestPtr request);
PacketPtr write_shared_memory(CPUPtr this, RequestPtr request);
PacketPtr read_shared_memory(CPUPtr this, RequestPtr request);
PacketPtr check_shared_memory_full(CPUPtr this, RequestPtr request);
PacketPtr check_shared_memory_empty(CPUPtr this, RequestPtr request);

//helper functions
PacketPtr handleRequest(CPUPtr this, RequestPtr request);
void wakeIOThreads(CPUPtr this);

#endif

